iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 17
1

發現忘記寫單元測試了
今天會幫
Day16 MVVM專案-3 RecyclerView
Day15 MVVM專案-2 Simple Fragment -3 DI
Day9 MVVM專案-1a

補上單元測試

build.gradle(module:app)

dependencies{
 def mock_version = "1.9.2"
    testImplementation "io.mockk:mockk:$mock_version"
    androidTestImplementation "io.mockk:mockk-android:$mock_version"
}

S01ViewModelTest.kt

class S01ViewModelTest {

    @Rule
    @JvmField
    val rule = InstantTaskExecutorRule()

    private val viewModel by lazy { Stage01ViewModel() }

    private fun setValues(value: String) {
        viewModel.left.value = value
        viewModel.right.value = value
    }

    @Test
    fun plus() {
        // given
        val givenVal = "1"
        setValues(givenVal)

        // when
        viewModel.plus()

        // then
        Assert.assertEquals("2", viewModel.result.value)
    }


    @Test
    fun clear() {
        // given
        val givenVal = "1"
        setValues(givenVal)

        // when
        viewModel.clear()

        // then
        Assert.assertEquals("", viewModel.left.value)
        Assert.assertEquals("", viewModel.right.value)
        Assert.assertEquals("", viewModel.result.value)
    }
}

S01aViewModelTest.kt

class S01aViewModelTest {
    @Rule
    @JvmField
    val rule = InstantTaskExecutorRule()

    @Test
    fun result_only_when_two_values_changed() {
        val viewModel = Stage01ViewModel()
        val lifecycle = LifecycleRegistry(mockk()).apply {
            handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
        }

        // given
        val givenLeft = "1"
        val givenRight = "1"

        val visibleResultObserver = mockk<(Boolean?) -> Unit>().also {
            every { it.invoke(false) } returns Unit // for initial value
        }
        viewModel.result.observe({ lifecycle }) {}
        viewModel.visibleResult.observe({ lifecycle }, visibleResultObserver)

        // when
        viewModel.left.value = givenLeft
        // then
        Assert.assertSame(viewModel.result.value, "")

        // when
        every { visibleResultObserver.invoke(true) } returns Unit
        viewModel.right.value = givenRight

        // then
        verify { visibleResultObserver.invoke(true) }
        Assert.assertEquals("2", viewModel.result.value)
    }
}

S02ViewModelTest.kt

class S02ViewModelTest {
    @Rule
    @JvmField
    val rule = InstantTaskExecutorRule()

    private fun justTrue() = true

    @Test
    fun tryResult_and_applyScore() {
        val viewModel = Stage02ViewModel(::justTrue)

        // given
        // none

        // when
        viewModel.tryResult()

        // then
        Assert.assertEquals(Stage02ViewModel.TryResult.SUCCESS, viewModel.result.value)

        // given
        // none

        // when
        viewModel.applyScore()

        // then
        Assert.assertEquals(1, viewModel.score.value)
    }

}

S02DIViewModelTest.kt

val S02DITestViewModelModule = Kodein.Module("S02ViewModel") {
    bind<() -> Boolean>() with singleton { { true } }
}

class S02DIViewModelTest : KodeinAware {

    @Rule
    @JvmField
    val rule = InstantTaskExecutorRule()

    override val kodein: Kodein = Kodein.lazy {
        import(S02DITestViewModelModule)
    }

    @Test
    fun tryResult_and_applyScore() {
        val viewModel by kodein.newInstance { Stage02ViewModel(instance()) }
        // given
        // none

        // when
        viewModel.tryResult()
        // then
        Assert.assertEquals(Stage02ViewModel.TryResult.SUCCESS, viewModel.result.value)

        // when
        viewModel.applyScore()
        // then
        Assert.assertEquals(1, viewModel.score.value)
    }

}

S03ViewModelTest.kt

class S03ViewModelTest {
    @Rule
    @JvmField
    val rule = InstantTaskExecutorRule()

    @Test
    fun add() {
        val viewModel = S03ViewModel()

        // given
        val beforeSize = viewModel.memos.value!!.size
        val givenNewContent = "new content"

        viewModel.newContent.value = givenNewContent

        // when
        viewModel.add()

        // then
        Assert.assertEquals(givenNewContent, viewModel.memos.value!![0].content)
        Assert.assertEquals(beforeSize + 1, viewModel.memos.value!!.size)
    }

    @Test
    fun remove() {
        val viewModel = S03ViewModel()

        // given
        val beforeSize = viewModel.memos.value!!.size
        val givenIdxWillBeRemove = 3
        val beforeMemo = viewModel.memos.value!![givenIdxWillBeRemove]

        // when
        viewModel.remove(viewModel.memos.value!!, givenIdxWillBeRemove)

        // then
        Assert.assertFalse(beforeMemo == viewModel.memos.value!![givenIdxWillBeRemove])
        Assert.assertEquals(beforeSize - 1, viewModel.memos.value!!.size)
    }

}

solution
https://github.com/mars1120/jetpackMvvmDemo/tree/update_unit_test


上一篇
Day16 MVVM專案-3 RecyclerView
下一篇
Day18 MVVM專案-4 RequestPermission
系列文
Android × CI/CD 如何用基本的MVVM專案實現 CI/CD 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言